package org.example.infrastructure.persistent.redis;

import org.redisson.api.*;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.concurrent.TimeUnit;

/**
 * Redis 服务 - Redisson
 *
 * @author Fuzhengwei bugstack.cn @小傅哥
 */
@Service("redissonService")
public class RedissonService implements IRedisService {

    @Resource
    private RedissonClient redissonClient;

    public <T> void setValue(String key, T value) {
        redissonClient.<T>getBucket(key).set(value);
    }

    @Override
    public <T> void setValue(String key, T value, long expired) {
        RBucket<T> bucket = redissonClient.getBucket(key);
        bucket.set(value, Duration.ofMillis(expired));
    }

    public <T> T getValue(String key) {
        return redissonClient.<T>getBucket(key).get();
    }

    @Override
    public <T> RQueue<T> getQueue(String key) {
        return redissonClient.getQueue(key);
    }

    @Override
    public <T> RBlockingQueue<T> getBlockingQueue(String key) {
        /*
        getBlockingQueue 是 Redisson 提供的一个方法，用于获取一个分布式的 阻塞队列（RBlockingQueue）;
        RBlockingQueue 是 Redisson 中提供的分布式队列，它允许在多个进程或线程之间进行消息传递或任务调度;
        它的 "阻塞" 特性意味着当队列为空时，调用 take() 等方法的线程会被阻塞，直到队列中有新元素可用;
        key 是 Redis 中存储该队列的标识符。调用 getBlockingQueue(key) 方法后，Redisson 会根据这个 key 获取到对应的分布式阻塞队列。如果 Redis 中没有该队列，它会自动创建一个新的；
        offer(T e)：向队列中添加一个元素；
        poll()：从队列中移除并返回一个元素（如果队列为空则返回 null）；
        take()：从队列中移除并返回一个元素（如果队列为空，则会阻塞，直到有元素可以返回）；
        put(T e)：向队列中添加一个元素（如果队列已满，则会阻塞，直到有空间可以放置元素）；
         */
        return redissonClient.getBlockingQueue(key);
    }

    @Override
    public <T> RDelayedQueue<T> getDelayedQueue(RBlockingQueue<T> rBlockingQueue) {
        /*
        getDelayedQueue(rBlockingQueue) 是 Redisson 提供的方法，用于将一个 RBlockingQueue 转换为 RDelayedQueue;
        RBlockingQueue<T>：这是一个标准的分布式阻塞队列，它允许元素被添加到队列中并阻塞线程直到元素被取出;
        RDelayedQueue<T>：这是一个延迟队列，允许队列中的元素在一定的延迟时间之后才能被消费。即，元素在队列中被放入时可以指定一个延迟时间，消费者必须等待这个时间过后才能取出元素;
         */
        return redissonClient.getDelayedQueue(rBlockingQueue);
    }

    @Override
    public void setAtomicLong(String key, long value) {
        redissonClient.getAtomicLong(key).set(value);
    }

    @Override
    public Long getAtomicLong(String key) {
         return redissonClient.getAtomicLong(key).get();
    }

    @Override
    public long incr(String key) {
        return redissonClient.getAtomicLong(key).incrementAndGet();
    }

    @Override
    public long incrBy(String key, long delta) {
        return redissonClient.getAtomicLong(key).addAndGet(delta);
    }

    @Override
    public long decr(String key) {
        /*
        getAtomicLong(key) 方法用于获取一个名为 key 的 原子长整型（AtomicLong） 对象;
        AtomicLong 是一种线程安全的 long 类型包装器，支持原子性操作，比如递增、递减、获取值等;
        redissonClient.getAtomicLong(key) 会返回一个 AtomicLong 对象，它对应 Redis 中指定 key 的值。如果 key 不存在，Redisson 会创建一个新的 AtomicLong，并将其值初始化为 0;
        decrementAndGet() 是 AtomicLong 类的一个方法，它会将当前值减 1，然后返回减 1 后的新值。
        这是一个原子操作，意味着它在多线程环境中也是安全的。即使多个线程同时调用该方法，每个线程都会看到最新的值，并且保证递减操作不会出现竞态条件。
        */
        return redissonClient.getAtomicLong(key).decrementAndGet();
    }

    @Override
    public long decrBy(String key, long delta) {
        return redissonClient.getAtomicLong(key).addAndGet(-delta);
    }

    @Override
    public void remove(String key) {
        redissonClient.getBucket(key).delete();
    }

    @Override
    public boolean isExists(String key) {
        return redissonClient.getBucket(key).isExists();
    }

    public void addToSet(String key, String value) {
        RSet<String> set = redissonClient.getSet(key);
        set.add(value);
    }

    public boolean isSetMember(String key, String value) {
        RSet<String> set = redissonClient.getSet(key);
        return set.contains(value);
    }

    public void addToList(String key, String value) {
        RList<String> list = redissonClient.getList(key);
        list.add(value);
    }

    public String getFromList(String key, int index) {
        RList<String> list = redissonClient.getList(key);
        return list.get(index);
    }

    @Override
    public <K, V> RMap<K, V> getMap(String key) {
        return redissonClient.getMap(key);
    }

    public void addToMap(String key, String field, String value) {
        RMap<String, String> map = redissonClient.getMap(key);
        map.put(field, value);
    }

    public String getFromMap(String key, String field) {
        RMap<String, String> map = redissonClient.getMap(key);
        return map.get(field);
    }

    @Override
    public <K, V> V getFromMap(String key, K field) {
        return redissonClient.<K, V>getMap(key).get(field);
    }

    public void addToSortedSet(String key, String value) {
        RSortedSet<String> sortedSet = redissonClient.getSortedSet(key);
        sortedSet.add(value);
    }

    @Override
    public RLock getLock(String key) {
        return redissonClient.getLock(key);
    }

    @Override
    public RLock getFairLock(String key) {
        return redissonClient.getFairLock(key);
    }

    @Override
    public RReadWriteLock getReadWriteLock(String key) {
        return redissonClient.getReadWriteLock(key);
    }

    @Override
    public RSemaphore getSemaphore(String key) {
        return redissonClient.getSemaphore(key);
    }

    @Override
    public RPermitExpirableSemaphore getPermitExpirableSemaphore(String key) {
        return redissonClient.getPermitExpirableSemaphore(key);
    }

    @Override
    public RCountDownLatch getCountDownLatch(String key) {
        return redissonClient.getCountDownLatch(key);
    }

    @Override
    public <T> RBloomFilter<T> getBloomFilter(String key) {
        return redissonClient.getBloomFilter(key);
    }

    @Override
    public Boolean setNx(String key) {
        /*
        getBucket(key) 方法返回一个 RBucket 对象，该对象代表 Redis 中存储的一个单一的键值对;
        在 Redis 中，"bucket" 就是一个简单的键值存储，可以是任何类型的值（字符串、数字等）;
        trySet("lock") 是 RBucket 对象的一个方法。它尝试设置 Redis 中指定 key 的值为 "lock"，但会检查该 key 是否已经存在；
        如果 key 不存在（即 Redis 中没有这个 key），trySet 会设置 key 的值为 "lock"，并返回 true，表示成功获取锁；
        如果 key 已经存在（即已经有一个值），trySet 不会修改它，并返回 false，表示锁没有被成功获取；
         */
        return redissonClient.getBucket(key).trySet("lock");
    }

    @Override
    public Boolean setNx(String lockKey, long expireMillis, TimeUnit timeUnit) {
        return redissonClient.getBucket(lockKey).trySet("lock",expireMillis,timeUnit);
    }


}
